/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package poker.geneticAlgorithm;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

/**
 * Two point crossover.
 * 
 * 
 * @author Benjamin L. Brodie <blbrodie@gmail.com>
 */
public class TwoPointCrossover implements Crossover<Individual<Double>>{
    private Random random;
    
    public TwoPointCrossover(){
        this.random = new Random();
    }

    /**
     * Two point crossover
     * 
     * 
     * @param individuals
     * @return 
     */
    public List<Individual<Double>> cross(List<Individual<Double>> individuals) {
        int len = individuals.get(0).getList().size();
        
        int start = random.nextInt(len+1);
        int end = random.nextInt(len+1);
        
        //swap
        if (start > end){
            int temp = start;
            start = end;
            end = temp;
        }
        
        return cross(individuals, start, end);
        
        
    }
    
    /**
     * Two point crossover with predefined start and end positions. Start(inclusive) and
     * end(exclusive). Useful for testing.
     * 
     * @param individuals
     * @param start
     * @param end
     * @return 
     */
    public List<Individual<Double>> cross(List<Individual<Double>> individuals,
                                                            int start, int end){
        
        
        if (individuals.size() > 2){
            throw new IllegalArgumentException("crossover can only take a list of two");
            
        }
        
        if (start > end){
            throw new IllegalArgumentException("start position must be greater than end position");
        }
        
        List<Double> parent_1 = individuals.get(0).getList();
        List<Double> parent_2 = individuals.get(1).getList();
        
        
        List<Double> child_1 = newChild(parent_1, parent_2, start, end);
        List<Double> child_2 = newChild(parent_2, parent_1, start, end);
        
        
        return new ArrayList<Individual<Double>>
                (Arrays.asList(new WeightsIndividual(child_1),
                               new WeightsIndividual(child_2)));
        
    }
    
    /**
     * returns a new child list of the parents and start (inclusive) and end (exclusive)
     * @param firstParent
     * @param secondParent
     * @param start
     * @param end
     * @return 
     */
    private List<Double> newChild
      (List<Double> firstParent, List<Double> secondParent, int start, int end){
        
        List<Double> child = new ArrayList<Double>();
        
        child.addAll(secondParent.subList(0, start));
        child.addAll(firstParent.subList(start, end));
        child.addAll(secondParent.subList(end, secondParent.size()));
        
        return child;
        
    }
    
}
